/*
 * @Descripttion: 模型
 * @Author: 张正兴
 * @Date: 2021-12-27 12:30:16
 * @LastEditors: 张正兴
 */
import * as THREE from 'three'
import {OBJLoader} from 'three/examples/jsm/loaders/OBJLoader'
import {FBXLoader} from "three/examples/jsm/loaders/FBXLoader";

// 模拟材质 真实材质模拟
const realMaterial = () => {
  // 环境贴图
  const loader = new THREE.CubeTextureLoader();
  loader.setPath('/img/');
  const textureCube = loader.load(['01.jpg', '01.jpg', '01.jpg', '01.jpg', '01.jpg', '01.jpg']);
  // 开启立方体折射
  textureCube.mapping = THREE.CubeRefractionMapping;

  // 基础材质
  let textureLoader = new THREE.TextureLoader();
  let diffuseReflection = textureLoader.load("/img/01.jpg");
  let normal = textureLoader.load("/img/02.jpg");
  let bump = textureLoader.load("/img/03.jpg");
  let dirt = textureLoader.load("/img/04.jpg");

  // 该材质是真实材质无法模拟透明效果
  const material = new THREE.MeshStandardMaterial();

  // 漫反射
  material.map = diffuseReflection;

  // 法线
  material.normalMap = normal;

  // 凹凸
  material.bumpMap = bump;

  // 粗糙
  material.roughness = 0.2
  material.roughnessMap = dirt

  // 环境贴图
  material.envMap = textureCube
  // reflectivity: 0.1,

  // 金属
  // material.metalness = 0.5;
  material.metalnessMap = dirt

  //自发光
  // material.emissive = new THREE.Color( 0xff0000 );
  // material.emissiveMap = Texture
  // material.emissiveIntensity = 0.2 //发光强度

  // 不透明度
  // material.transparent = true;
  // material.opacity = 0.5

  return material;
}

// 正方体模型
const boxMesh = () => {
  // 圆环
  // let geometry = new THREE.TorusGeometry(10, 3, 16, 100);
  // 方体
  let geometry = new THREE.BoxGeometry(15, 15, 15)
  const mesh = new THREE.Mesh(geometry, realMaterial())
  mesh.receiveShadow = true
  mesh.castShadow = true
  return mesh
}

// 添加一个平面
const planeMesh = () => {
  const planeGeo = new THREE.PlaneGeometry(80, 80, 1, 1) //创建平面
  const planeMat = new THREE.MeshPhongMaterial({
    //创建材料
    color: 0x666666
  })
  const planeMesh = new THREE.Mesh(planeGeo, planeMat) //创建网格模型
  planeMesh.position.set(0, 0, 0) //设置平面的坐标
  planeMesh.rotation.x = -0.5 * Math.PI //将平面绕X轴逆时针旋转90度
  planeMesh.receiveShadow = true
  planeMesh.castShadow = true
  return planeMesh
}

// 添加一个模型
const Obj = () => {
  // 创建一个组用来存储网格
  const group = new THREE.Group()
  const sprite = new THREE.TextureLoader().load('/img/01.jpg')
  const planeMatA = new THREE.MeshPhongMaterial({
    // 创建材料
    // color: 777777,
    map: sprite,
    // metalness: 0.8,
    // bumpMap: sprite,
    // roughness: 0.8,
    // wireframe: false
  })
  const planeMatB = new THREE.MeshPhongMaterial({
    //创建材料
    // color: 777777,
    // map: sprite,
    // metalness: 0.8,
    bumpMap: sprite,
    roughness: 0.8,
    wireframe: false
  })

  //let objLoader = new OBJLoader()
  let objLoader = new FBXLoader()

  let mixerSum = {}

  //加载模型
  objLoader.load('/mode/untitled.fbx', mesh => {
    //模型已组的方式储存需要进行遍历
    // mesh.children.forEach(node => {
    //   node.material = planeMatA
    //   node.castShadow = true
    //   node.receiveShadow = true
    // })

    // mesh.children[0].material = planeMatA
    // mesh.children[1].material = planeMatB
    mesh.scale.set(.1, .1, .1)
    mesh.position.set(0, 0, 0)

    const mixer = new THREE.AnimationMixer(mesh);

    // 放入动画播放 (这种直接播放模式不能进行操控)
    // mixer.clipAction(mesh.animations[0]).play();

    // 返回动画控制器
    const AnimationAction = mixer.clipAction(mesh.animations[0]);
    // AnimationAction.timeScale = 5; //默认1，可以调节播放速度
    AnimationAction.loop = THREE.LoopOnce; //不循环播放
    AnimationAction.clampWhenFinished = true; //暂停在最后一帧播放的状态
    // 设置播放区间10~18   关键帧数据总时间是20（剪辑当前动画）
    AnimationAction.time = 0; //操作对象设置开始播放时间
    mesh.animations[0].duration = 2;//剪辑对象设置播放结束时间
    AnimationAction.play(); //开始播放

    // 暂停动画
    // setTimeout(() => {
    //   AnimationAction.paused = true;
    // }, 1000)
    // setTimeout(() => {
    //   AnimationAction.paused = false;
    // }, 2000)

    // 这里进行模拟固定在某个时间段
    // let i = 0.1
    // setInterval(() => {
    //   i = i + 0.1
    //   AnimationAction.time = 2 + i; //操作对象设置开始播放时间
    //   mesh.animations[0].duration = 2 + i;//剪辑对象设置播放结束时间
    //   AnimationAction.play(); //开始播放
    // }, 200)

    // 停止动画 (这里进行的片断剪辑停止动画再重新播放)
    // setTimeout(() => {
    //   AnimationAction.stop(); //停止动画播放
    //   AnimationAction.time = 2; //操作对象设置开始播放时间
    //   mesh.animations[0].duration = 4;//剪辑对象设置播放结束时间
    //   AnimationAction.play();
    // }, 2000)

    // 这里会重置当前动画
    // setInterval(() => {
    //   AnimationAction.reset()
    // }, 5000)

    // 暂停动画
    // http://www.yanhuangxueyuan.com/Three.js/

    // 这里克隆一个新对象
    // const mesh1 = mesh.clone()

    mixerSum.mixer = mixer

    group.add(mesh)
  })

  return {mesh: group, mixer: mixerSum}
}

// 画3d饼图
const pie3D = (K = 10, J = 20, color = 'rgb(193,171,31)', HT = 20) => {
  const myJson = []

  const R = 30 //圆弧半径
  const N = 200 //分段数量
  // 批量生成圆弧上的顶点数据

  for (let i = K; i < J; i++) {
    const angle = ((2 * Math.PI) / N) * i
    const x = R * Math.sin(angle)
    const y = R * Math.cos(angle)
    myJson.push({x: x, y: y})
  }

  for (let i = J - 1; i > K - 1; i--) {
    const angle = ((2 * Math.PI) / N) * i
    const x = 50 * Math.sin(angle)
    const y = 50 * Math.cos(angle)
    myJson.push({x: x, y: y})
  }

  const shape = new THREE.Shape()

  shape.moveTo(myJson[0].x, myJson[0].y)
  for (let i = 1; i < myJson.length; i++) {
    shape.lineTo(myJson[i].x, myJson[i].y)
  }

  const extrudeSettings = {
    steps: 1,
    depth: HT,
    bevelEnabled: false,
    bevelThickness: 1,
    bevelSize: 1,
    bevelSegments: 1
  }

  const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings)
  geometry.computeVertexNormals()
  const material = new THREE.MeshPhongMaterial({
    color: color,
    // wireframe: true, //是否显示网格
  })

  material.shading = THREE.SmoothShading
  // const material = new THREE.MeshLambertMaterial( { side: THREE.DoubleSide,color: color } );

  // 开启透明度
  material.transparent = true
  material.opacity = 0.8

  const mesh = new THREE.Mesh(geometry, material)
  mesh.receiveShadow = true
  mesh.castShadow = true
  mesh.rotateX(Math.PI * -0.5)

  return mesh
}

// 封装饼图
const pieSum = (
  value = [
    {name: '苹果', value: 100},
    {name: '梨', value: 50},
    {name: '葡萄', value: 50}
  ]
) => {
  let sum = 0
  value.forEach(item => {
    sum = sum + item.value
  })
  const proportion = value.map(item => item.value / sum)

  // 圆柱分割的数量
  const accurate = 200

  // 存放颜色
  const color = ['rgb(193,171,31)', 'rgb(31,47,193)', 'rgb(193,31,31)']

  // 用来存放网格的空物体
  const obj = new THREE.Object3D()

  let sumVal = 0,
    oldVal
  for (let i = 0; i < proportion.length; i++) {
    oldVal = sumVal
    sumVal = sumVal + parseInt(accurate * proportion[i])
    obj.add(pie3D(oldVal, sumVal + 1, color[i], 30))
  }

  obj.children.pop()
  obj.add(pie3D(oldVal, accurate + 1, color[color.length - 1], 30))

  return obj
}

// 精灵图
const elvesImg = () => {
  // 设置canvas贴图
  const canvas = document.createElement("canvas");
  canvas.width = 512;
  canvas.height = 512;
  const c = canvas.getContext('2d');

  c.fillStyle = "#000000"; //文本填充颜色
  c.font = "bold 48px 宋体"; //字体样式设置
  c.textBaseline = "middle"; //文本与fillText定义的纵坐标
  c.textAlign = "center"; //文本居中(以fillText定义的横坐标)
  c.fillText("郭隆邦", 100, 100);
  let texture = new THREE.CanvasTexture(canvas);

  // 精灵图片
  // const texture = new THREE.TextureLoader().load('/tu.jpeg')

  // 创建精灵材质对象SpriteMaterial
  const spriteMaterial = new THREE.SpriteMaterial({
    color: 0xff00ff, //设置精灵矩形区域颜色
    // rotation: Math.PI, //旋转精灵对象45度，弧度值
    map: texture //设置精灵纹理贴图
  })

// 更新canvas数据
  setTimeout(() => {
    c.clearRect(0, 0, 512, 512)
    c.fillStyle = "#000000"; //文本填充颜色
    c.font = "bold 48px 宋体"; //字体样式设置
    c.textBaseline = "middle"; //文本与fillText定义的纵坐标
    c.textAlign = "center"; //文本居中(以fillText定义的横坐标)
    c.fillText("张正兴", 100, 100);
    texture = new THREE.CanvasTexture(canvas);
    spriteMaterial.map = texture
  }, 1000)

  // 创建精灵模型对象，不需要几何体geometry参数
  const sprite = new THREE.Sprite(spriteMaterial)
  sprite.position.set(50, 50, 50)
  // 控制精灵大小，比如可视化中精灵大小表征数据大小
  sprite.scale.set(50, 50, 1) //// 只需要设置x、y两个分量就可以
  return sprite
}

// 车削
const turning = () => {
  const points = [
    new THREE.Vector2(50, 60),
    new THREE.Vector2(25, 0),
    new THREE.Vector2(50, -60),
    new THREE.Vector2(50, 60)
  ]
  const geometry = new THREE.LatheGeometry(points, 30, 0, Math.PI / 3)
  const material = new THREE.MeshPhongMaterial({
    color: 0x0000ff, //三角面颜色
    side: THREE.DoubleSide //两面可见
  }) //材质对象
  // material.wireframe = true;//线条模式渲染(查看细分数)
  const mesh = new THREE.Mesh(geometry, material) //旋转网格模型对象
  return mesh
}

export {boxMesh, planeMesh, Obj, pie3D, turning, pieSum, elvesImg}
